package com.engine.modules.ytht.util;

import java.security.Security;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;



public class AESpkcs7paddingUtil {

    /**
     * 密钥算法
     */
    private static final String KEY_ALGORITHM = "AES";

    /**
     * 加密/解密算法 / 工作模式 / 填充方式
     * Java 6支持PKCS5Padding填充方式
     * Bouncy Castle支持PKCS7Padding填充方式
     */
    private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS7Padding";

    /**
     * 偏移量，只有CBC模式才需要
     *  private final static String ivParameter = "0000000000000000";
     */


    /**
     * AES要求密钥长度为128位或192位或256位，java默认限制AES密钥长度最多128位
     */
    public static String sKey="" ;

    /**
     * 编码格式
     */
    public static final String ENCODING = "utf-8";


    static {
        /**
                               * 如果是PKCS7Padding填充方式，则必须加上下面这行
         */
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * AES加密
     * @param source	源字符串
     * @param key	密钥
     * @return	加密后的密文
     * @throws Exception
     */
    public static String encrypt(String source,String ivParameter, String key) throws Exception {
        byte[] sourceBytes = source.getBytes(ENCODING);
        byte[] keyBytes = key.getBytes(ENCODING);
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM, "BC");
        IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes(ENCODING));
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, KEY_ALGORITHM),iv);
        byte[] decrypted = cipher.doFinal(sourceBytes);
        return Base64.encodeBase64String(decrypted);
    }

    /**
     * AES解密
     * @param encryptStr	加密后的密文
     * @param key	密钥
     * @return	源字符串
     * @throws Exception
     */
    public static String decrypt(String encryptStr,String ivParameter, String key) throws Exception {
        byte[] sourceBytes = Base64.decodeBase64(encryptStr);
        byte[] keyBytes = key.getBytes(ENCODING);
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM, "BC");
        IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes(ENCODING));
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(keyBytes, KEY_ALGORITHM),iv);
        byte[] decoded = cipher.doFinal(sourceBytes);
        return new String(decoded, ENCODING);
    }


    public static void main(String[] args) throws Exception {
        /**
         * 参考
         * https://moln.site/2018/06/22/crypto-js-aes-usage.html
         * http://jser.io/2014/08/19/how-to-use-aes-in-crypto-js-to-encrypt-and-decrypt
         * https://juejin.cn/post/6844904117970698248
         *
         * key生成：
         * 以AES密钥16位为例，取应用登陆态sessionid的后16位
         *
         *
         * 加密:
         * 1.AES加密生成加密字节数组
         * 2.Base64编码第1步的字节数组
         *
         * 解密:
         * 1.Base64解码加密请求报文生成字节数组
         * 2.AES解密加密第1步的加密字节数据
         * String key = "1234567890123456";
         */




        /**
         	*  加密
         */
        long lStart = System.currentTimeMillis();
        /**
        *String enString = AESpkcs7paddingUtil.encrypt("abcd中文测试加标点符号！@#￥%……&*（+——）（*&~，。，；,,/;lkk;ki;'[p]./,'\\467646789",key);
        *System.out.println("加密后的字串是：" + enString);
         **/
        long lUseTime = System.currentTimeMillis() - lStart;
        System.out.println("加密耗时：" + lUseTime + "毫秒");

        /**
         	*  解密
         */
        lStart = System.currentTimeMillis();
        /**
        String DeString = AESpkcs7paddingUtil.decrypt(enString,key);
        System.out.println("解密后的字串是：" + DeString);
        **/
        lUseTime = System.currentTimeMillis() - lStart;
        System.out.println("解密耗时：" + lUseTime + "毫秒");


        /**
                        * 直接解密字符串
         */
        /**
        String strDecryptByJava = AESpkcs7paddingUtil.decrypt(enString,key);
        if (strDecryptByJava.equals(DeString)) {
            System.out.println("检验成功");


        }

        System.out.println("js加密后的字符串解密是：" + strDecryptByJava);
          **/
    }

}
